/**
 *                            License
 * THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS  
 * CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). 
 * THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW.  
 * ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR  
 * COPYRIGHT LAW IS PROHIBITED.
 * 
 * BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND  
 * AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE  
 * MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED 
 * HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
 * 
 */
package com.lineage.server;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import com.lineage.configure.Config;
import com.lineage.server.model.monitor.L1PcMonitor;

/**
 * 通用线程池.
 */
public class GeneralThreadPool {

    // ThreadPoolManager 借用
    /**
     * 优先级线程工厂.<br>
     * <br>
     * 根据需要创建新线程的对象.<br>
     * 使用线程工厂就无需再手工编写对 new Thread 的调用了，从而允许应用程序使用特殊的线程子类、属性等等。
     */
    private static class PriorityThreadFactory implements ThreadFactory {
        /** 优先级. */
        private final int _prio;
        /** 线程名称. */
        private final String _name;
        /** 使用初始值 1 创建新的 AtomicInteger(可以用原子方式更新的 int 值). */
        private final AtomicInteger _threadNumber = new AtomicInteger(1);
        /**
         * 线程组表示一个线程的集合.<br>
         * 此外，线程组也可以包含其他线程组。线程组构成一棵树，在树中，除了初始线程组外，每个线程组都有一个父线程组。
         * 
         * 允许线程访问有关自己的线程组的信息，但是不允许它访问有关其线程组的父线程组或其他任何线程组的信息。
         */
        private final ThreadGroup _group;

        /**
         * 优先级线程工厂.
         * 
         * @param name
         *            线程名称
         * @param prio
         *            优先级
         */
        public PriorityThreadFactory(final String name, final int prio) {
            this._prio = prio;
            this._name = name;
            this._group = new ThreadGroup(this._name); // 构造一个新线程组
        }

        /*
         * (non-Javadoc)
         * 
         * @see java.util.concurrent.ThreadFactory#newThread(java.lang.Runnable)
         */
        @Override
        public Thread newThread(final Runnable r) {
            final Thread t = new Thread(this._group, r);
            t.setName(this._name + "-" + this._threadNumber.getAndIncrement());
            t.setPriority(this._prio);
            return t;
        }
    }

    /** 实例. */
    private static GeneralThreadPool _instance;

    /** 核心线程池大小. */
    private static final int SCHEDULED_CORE_POOL_SIZE = 10;

    /**
     * 当实例为空时才新创建一个(多线程下的单例模式).
     * 
     * @return 实例
     */
    public static synchronized GeneralThreadPool getInstance() {
        if (_instance == null) {
            _instance = new GeneralThreadPool();
        }
        return _instance;
    }

    /** 通用的ExecutorService(执行服务). */
    private Executor _executor;

    /**
     * 通用的ScheduledExecutorService.<br>
     * (一个 ExecutorService，可安排在给定的延迟后运行或定期执行的命令).
     */
    private final ScheduledExecutorService _scheduler;

    /**
     * 监测玩家专用的ScheduledExecutorService.<br>
     * (一个 ExecutorService，可安排在给定的延迟后运行或定期执行的命令).
     */
    private final ScheduledExecutorService _pcScheduler;

    /**
     * (AutoUpdate:约6ms,ExpMonitor:极小)<br>
     * 每20人增加一个PoolSize.
     */
    private final int _pcSchedulerPoolSize = 1 + Config.MAX_ONLINE_USERS / 20;

    /**
     * 通用线程池.
     */
    private GeneralThreadPool() {
        if (Config.THREAD_P_TYPE_GENERAL == 1) {
            // 创建一个可重用固定线程集合的线程池，以共享的无界队列方式来运行这些线程
            this._executor = Executors
                    .newFixedThreadPool(Config.THREAD_P_SIZE_GENERAL);
        } else if (Config.THREAD_P_TYPE_GENERAL == 2) {
            // 创建一个可根据需要创建新线程的线程池，但是在以前构造的线程可用时将重用它们
            this._executor = Executors.newCachedThreadPool();
        } else {
            this._executor = null;
        }
        // 创建一个可重用固定线程集合的线程池，以共享的无界队列方式来运行这些线程，在需要时使用提供的 ThreadFactory 创建新线程
        this._scheduler = Executors.newScheduledThreadPool(
                SCHEDULED_CORE_POOL_SIZE, new PriorityThreadFactory(
                        "GerenalSTPool", Thread.NORM_PRIORITY)); // 以默认的优先级指派给线程
        // 创建一个可重用固定线程集合的线程池，以共享的无界队列方式来运行这些线程，在需要时使用提供的 ThreadFactory 创建新线程
        this._pcScheduler = Executors.newScheduledThreadPool(
                this._pcSchedulerPoolSize, new PriorityThreadFactory(
                        "PcMonitorSTPool", Thread.NORM_PRIORITY));
    }

    /**
     * 使该线程开始执行；Java 虚拟机调用该线程的 run 方法.
     * 
     * @param r
     *            - 可运行的任务
     */
    public void execute(final Runnable r) {
        if (this._executor == null) {
            final Thread t = new Thread(r); // 分配新的 Thread 对象
            t.start();
        } else {
            // 在未来某个时间执行给定的命令。
            // 该命令可能在新的线程、已入池的线程或者正调用的线程中执行，这由 Executor 实现决定
            this._executor.execute(r);
        }
    }

    /**
     * 使该线程开始执行；Java 虚拟机调用该线程的 run 方法.
     * 
     * @param t
     *            - 其 run 方法被调用的对象
     */
    public void execute(final Thread t) {
        t.start();
    }

    /**
     * 监测玩家专用的ScheduledExecutorService.<br>
     * 一个延迟的、结果可接受的操作，可将其取消。通常已安排的 future 是用 ScheduledExecutorService 安排任务的结果
     * 
     * @param r
     *            - 要执行的功能
     * @param delay
     *            - 从现在开始延迟执行的时间
     * @return 创建并执行在给定延迟后启用的一次性操作
     */
    public ScheduledFuture<?> pcSchedule(final L1PcMonitor r, final long delay) {
        try {
            if (delay <= 0) {
                // 在未来某个时间执行给定的命令。
                // 该命令可能在新的线程、已入池的线程或者正调用的线程中执行，这由 Executor 实现决定。
                this._executor.execute(r);
                return null;
            }
            // 创建并执行在给定延迟后启用的一次性操作。
            return this._pcScheduler.schedule(r, delay, TimeUnit.MILLISECONDS);
        } catch (final RejectedExecutionException e) {
            return null;
        }
    }

    /**
     * 监测玩家专用的ScheduledExecutorService.<br>
     * <br>
     * 创建并执行一个在给定初始延迟后首次启用的定期操作，后续操作具有给定的周期；<br>
     * 也就是将在 initialDelay 后开始执行，然后在 initialDelay+period 后执行，<br>
     * 接着在 initialDelay + 2 * period 后执行，依此类推。<br>
     * 如果任务的任一执行遇到异常，都会取消后续执行。否则，只能通过执行程序的取消或终止方法来终止该任务。<br>
     * 如果此任务的任何一个执行要花费比其周期更长的时间，则将推迟后续执行，但不会同时执行。 <br>
     * 
     * @param r
     *            - 要执行的任务
     * @param initialDelay
     *            - 首次执行的延迟时间
     * @param period
     *            - 连续执行之间的周期
     * 
     * @return 监测玩家专用的ScheduledExecutorService
     */
    public ScheduledFuture<?> pcScheduleAtFixedRate(final L1PcMonitor r,
            final long initialDelay, final long period) {
        return this._pcScheduler.scheduleAtFixedRate(r, initialDelay, period,
                TimeUnit.MILLISECONDS);
    }

    /**
     * 通用.<br>
     * <br>
     * 创建并执行在给定延迟后启用的一次性操作.
     * 
     * @param r
     *            - 要执行的任务
     * @param delay
     *            - 从现在开始延迟执行的时间
     * @return 通用的ScheduledExecutorService
     */
    public ScheduledFuture<?> schedule(final Runnable r, final long delay) {
        try {
            if (delay <= 0) {
                // 在未来某个时间执行给定的命令。
                // 该命令可能在新的线程、已入池的线程或者正调用的线程中执行，这由 Executor 实现决定。
                this._executor.execute(r);
                return null;
            }
            // 创建并执行在给定延迟后启用的一次性操作。
            return this._scheduler.schedule(r, delay, TimeUnit.MILLISECONDS);
        } catch (final RejectedExecutionException e) {
            return null;
        }
    }

    /**
     * 通用.<br>
     * <br>
     * 创建并执行一个在给定初始延迟后首次启用的定期操作，后续操作具有给定的周期；<br>
     * 也就是将在 initialDelay 后开始执行，然后在 initialDelay+period 后执行，<br>
     * 接着在 initialDelay + 2 * period 后执行，依此类推。<br>
     * 如果任务的任一执行遇到异常，都会取消后续执行。否则，只能通过执行程序的取消或终止方法来终止该任务。<br>
     * 如果此任务的任何一个执行要花费比其周期更长的时间，则将推迟后续执行，但不会同时执行。 <br>
     * 
     * @param r
     *            - 要执行的任务
     * @param initialDelay
     *            - 首次执行的延迟时间
     * @param period
     *            - 连续执行之间的周期
     * 
     * @return 通用的ScheduledExecutorService
     */
    public ScheduledFuture<?> scheduleAtFixedRate(final Runnable r,
            final long initialDelay, final long period) {
        return this._scheduler.scheduleAtFixedRate(r, initialDelay, period,
                TimeUnit.MILLISECONDS);
    }
}
